home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / exe2com.zip / EXE2COM.C < prev    next >
Text File  |  1993-01-04  |  9KB  |  304 lines

  1. /*
  2.     exe2com 1.01 - an exe2bin replacement
  3.           by Chris Dunford/The Cove Software Group.
  4.     see exe2com.doc for more info.
  5.  
  6.     usage: exe2com file [file]
  7.     usage is the same as exe2bin except:
  8.         1. Output defaults to COM rather than BIN
  9.         2. Binary fixup option not supported
  10.         3. Checksum not verified
  11.         4. Provides more useful error messages, and a warning if a
  12.            COM file is being created with initial IP != 0x100.
  13.  
  14.     Compiler notes:
  15.         The original executable of this file was produced with the
  16.         Computer Innovations C86 compiler (v2.2).
  17.  
  18.     This program was knocked together in about an hour in response to
  19.     the removal of EXE2BIN from the standard DOS distribution disks.
  20.     Improvements/corrections are encouraged.
  21.  
  22.     Program donated to the public domain by the author.
  23.  
  24.     cjd 4/17/87
  25.  
  26.     Modified to run under Turbo C by Roger Schlafly, Borland.
  27.     (It may not run on C86 any more.)
  28.     Compile with
  29.       tcc -Id:\c -Ld:\c -mt -w -O -Z -p exe2com
  30.       exe2com exe2com
  31.     or
  32.       tcc -Id:\c -Ld:\c -M -mt -w -DDEBUG=1 -O -Z -p exe2com
  33.       exe2com exe2com
  34.  
  35.     rss 6/26/87
  36. */
  37.  
  38. #include <stdio.h>
  39.  
  40. #include <string.h>
  41. /* for unlink */
  42. #include <dos.h>
  43. /* for exit */
  44. #include <stdlib.h>
  45. /* for tolower */
  46. #include <ctype.h>
  47.  
  48. /* Conversion error codes */
  49. #define BADREAD  1
  50. #define BADWRITE 2
  51. #define BADSIG   3
  52. #define HASRELO  4
  53. #define HAS_SS   5
  54. #define HAS_CS   6
  55. #define BAD_IP   7
  56. #define TOO_BIG  8
  57.  
  58. /*
  59. **  Define structure of fixed-format part of EXE file header
  60. */
  61. struct exe_header {
  62.         char exe_sig[2];    /* EXE file signature: "MZ" */
  63.     unsigned excess,        /* Image size mod 512 (valid bytes in last page) */
  64.              pages,         /* # 512-byte pages in image */
  65.              relo_ct,       /* Count of relocation table entries */
  66.              hdr_size,      /* Size of header, in paragraphs */
  67.              min_mem,       /* Min required memory */
  68.              max_mem,       /* Max required memory */
  69.              ss,            /* Stack seg offset in load module */
  70.              sp,            /* Initial value of SP */
  71.              cksum,         /* File checksum */
  72.              ip,            /* Initial value of IP */
  73.              cs,            /* CS offset in load module */
  74.              relo_start,    /* Offset of first relo item */
  75.              ovl_num;       /* Overlay number */
  76. } xh;
  77.  
  78. FILE *fi,                   /* Input file stream */
  79.      *fo;                   /* Output file stream */
  80.  
  81. char fin[129],              /* Input file name */
  82.      fon[129];              /* Output file name */
  83.  
  84.  
  85. unsigned long code_start,   /* Offset of program image in EXE file */
  86.               code_size;    /* Size of program image, in bytes */
  87.  
  88.  
  89. void err_xit (unsigned code);
  90. void convert (void);
  91. void read_hdr(void);
  92. void init (unsigned argc, char *argv[]);
  93.  
  94. char *lower (char *cp)
  95. {
  96. char *cp0;
  97.    for (cp0=cp; (*cp=tolower (*cp)) != 0; ++cp)
  98.            ;
  99.    return cp0;
  100. }
  101.  
  102. void cdecl main(unsigned argc, char *argv[])
  103. {
  104.     init (argc, argv);
  105.     read_hdr ();
  106.     convert ();
  107. }
  108.  
  109.  
  110. /*
  111. **  Initialize - get filenames and open/create files
  112. */
  113. void init (unsigned argc, char *argv[])
  114. {
  115. char *cp;
  116.  
  117.     printf ("exe2com 1.01\n");
  118.  
  119.     /* Check arg count */
  120.     if (argc < 2 || argc > 3) {
  121.         fprintf (stderr, "usage: exe2com file [file]\n");
  122.         exit (1);
  123.     }
  124.  
  125.     /* If argv[1] (the input file) has no extension, add .EXE */
  126.     strcpy (fin, lower (argv[1]));
  127.     if (!strchr (fin, '.'))
  128.         strcat (fin, ".exe");
  129.  
  130.     /* Get or construct output file name */
  131.     if (argc == 3)
  132.         strcpy (fon, lower (argv[2]));
  133.     else
  134.         strcpy (fon, fin);
  135.  
  136.     /* Check output extension--change EXE to COM, or add COM */
  137.     if (!(cp = strchr (fon, '.')))
  138.         strcat (fon, ".com");
  139.     else if (strcmp (cp, ".exe") == 0)
  140.         strcpy (cp, ".com");
  141.  
  142. #ifdef DEBUG
  143.     printf ("input=%s, output=%s\n", fin, fon);
  144. #endif
  145.  
  146.     /* Try to open input file */
  147.     if (!(fi = fopen (fin, "rb"))) {
  148.         fprintf (stderr, "exe2com: can't find input file %s\n", fin);
  149.         exit (1);
  150.     }
  151.  
  152.     /* Try to create output file */
  153.     if (!(fo = fopen (fon, "wb"))) {
  154.         fprintf (stderr, "exe2com: can't open output file %s\n", fin);
  155.         exit (1);
  156.     }
  157. }
  158.  
  159.  
  160. /*
  161. **  Read and check the EXE file header
  162. */
  163. void read_hdr(void)
  164. {
  165.  
  166.     /* Read the formatted portion of the header */
  167.     if (!fread (&xh, sizeof (struct exe_header), 1, fi))
  168.         err_xit (BADREAD);
  169.  
  170. #ifdef DEBUG
  171.     printf ("EXE file header:\n");
  172.     printf ("  signature      %c%c\n", xh.exe_sig[0], xh.exe_sig[1]);
  173.     printf ("  bytes last pg  %04x\n", xh.excess);
  174.     printf ("  pages          %04x\n", xh.pages);
  175.     printf ("  relo count     %04x\n", xh.relo_ct);
  176.     printf ("  header size    %04x\n", xh.hdr_size);
  177.     printf ("  min mem        %04x\n", xh.min_mem);
  178.     printf ("  max mem        %04x\n", xh.max_mem);
  179.     printf ("  ss             %04x\n", xh.ss);
  180.     printf ("  sp             %04x\n", xh.sp);
  181.     printf ("  checksum       %04x\n", xh.cksum);
  182.     printf ("  ip             %04x\n", xh.ip);
  183.     printf ("  cs             %04x\n", xh.cs);
  184.     printf ("  relo tbl start %04x\n", xh.relo_start);
  185.     printf ("  overlay nbr    %04x\n", xh.ovl_num);
  186. #endif
  187.  
  188.     /* Check header; to be convertible, must have:
  189.     **      -- first two bytes == "MZ"
  190.     **      -- no relocatable items
  191.     **      -- no stack segment
  192.     **      -- no code segment
  193.     **      -- IP == 0 or 100
  194.     */
  195.     if (strncmp (xh.exe_sig, "MZ", 2))
  196.         err_xit (BADSIG);
  197.     if (xh.relo_ct)
  198.         err_xit (HASRELO);
  199.     if (xh.ss || xh.sp)
  200.         err_xit (HAS_SS);
  201.     if (xh.ip != 0 && xh.ip != 0x100)
  202.         err_xit (BAD_IP);
  203.  
  204.     /* Compute offset of program image in module, and program size.
  205.     **
  206.     ** The program size is computed as follows; it cannot exceed 64K bytes:
  207.     **     512 * (# EXE pages - 1)
  208.     **   + valid bytes in last EXE page
  209.     **   - offset of program image in EXE file
  210.     **
  211.     ** Note that if the IP is nonzero, we will skip the first
  212.     ** IP bytes of the program image, and copy IP bytes fewer
  213.     ** than the actual size.
  214.     */
  215.     code_start = ((unsigned long) xh.hdr_size) << 4;
  216.     code_size = (unsigned long) (xh.pages-1) * 512 + xh.excess - code_start;
  217.     if (code_size >= 65536L)
  218.         err_xit (TOO_BIG);
  219.  
  220.     /* Issue a warning if COM file and IP != 0x100 */
  221.     if (!strcmp (strchr (fon, '.'), ".com") && xh.ip != 0x100)
  222.         fprintf (stderr, "exe2com warning: COM file, initial IP not 100H\n");
  223.  
  224. }
  225.  
  226.  
  227.  
  228. /*
  229. **  Convert the file.  Nothing to do, really, other than
  230. **  reading the image (which follows the header), and
  231. **  dumping it back out to disk.
  232. */
  233. void convert (void)
  234. {
  235. char buffer[512];
  236. unsigned wsize;
  237.  
  238.     /* Seek to start of program image, skipping IP bytes */
  239.     if (fseek (fi, code_start+xh.ip, 0) != 0)
  240.         err_xit (BADREAD);
  241.  
  242.     /* Reduce the "remaining" byte count by IP bytes */
  243.     code_size -= xh.ip;
  244.  
  245.     /* Read blocks and copy to output */
  246.     while (code_size) {
  247.  
  248.         /* Read block */
  249.         if (!fread (buffer, 1, 512, fi))
  250.             err_xit (BADREAD);
  251.  
  252.         /* Set count of bytes to write, write block */
  253.         wsize = (unsigned) (code_size > 512 ? 512 : code_size);
  254.         if (!fwrite (buffer, wsize, 1, fo))
  255.             err_xit (BADWRITE);
  256.  
  257.         /* Subtract bytes written from remaining byte count */
  258.         code_size -= wsize;
  259.     }
  260.  
  261.     /* All done, close the two files */
  262.     fclose (fi);
  263.     fclose (fo);
  264. }
  265.  
  266.  
  267. /*
  268. **  Display an error message, delete output file, exit.
  269. */
  270. void err_xit (unsigned code)
  271. {
  272. char msg[64];
  273.  
  274.     switch (code) {
  275.         case BADREAD:   strcpy (msg, "error reading EXE header");
  276.                         break;
  277.         case BADWRITE:  strcpy (msg, "error writing output file");
  278.                         break;
  279.         case BADSIG:    strcpy (msg, "invalid EXE file signature");
  280.                         break;
  281.         case HASRELO:   strcpy (msg, "EXE has relocatable items");
  282.                         break;
  283.         case HAS_SS:    strcpy (msg, "EXE has stack segment");
  284.                         break;
  285.         case HAS_CS:    strcpy (msg, "EXE has nonzero CS");
  286.                         break;
  287.         case BAD_IP:    strcpy (msg, "IP not 0 or 100H");
  288.                         break;
  289.         case TOO_BIG:   strcpy (msg, "program exceeds 64K");
  290.                         break;
  291.         default:        strcpy (msg, "unknown error");
  292.     }
  293.  
  294.     fprintf (stderr, "exe2com: %s, can't convert\n", msg);
  295.  
  296.     /* Close two files and delete partial output */
  297.     fclose (fi);
  298.     fclose (fo);
  299.     unlink (fon);
  300.  
  301.     /* Exit with errorlevel 1 */
  302.     exit (1);
  303. }
  304.